#include <bits/stdc++.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

using namespace std;

string testFile = "/data/test_data.txt";
string resultFile = "/projects/student/result.txt";

int node_num = 0;
uint nodes[2*280000];
int G[280000][50];//正向图
int RG[280000][50];//反向图
int len[280000];//正向图每个顶点的邻接表长度
int rlen[280000];//反向图每个顶点的邻接表长度

int ans3[500000][3], p3=0;//存环，记录个数
int ans4[500000][4], p4=0;
int ans5[1000000][5], p5=0;
int ans6[2000000][6], p6=0;
int ans7[3000000][7], p7=0;
char buf[77*3*1000000];//写数据时的缓存
bool vis[280000];//记录顶点是否遍历过
int avl[280000];//在每次剪枝中记录顶点的可达性

inline unsigned int parse(char** s){
	char *p = *s;
	unsigned int val = *(p++) - '0';
	while(*p != ','){
		val = 10*val + *(p++) - '0';
	}
	*s = p+1;
	return val;
}
void loadData_and_createGrap(){
	int fd = open(testFile.c_str(), O_RDONLY);
    int file_size = lseek(fd, 0, SEEK_END);
    char* p_map =(char*)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
	char *p = p_map;
	uint inputs[2*280000], n=0;
	while(*p != '\0'){
		inputs[n++]=(parse(&p));
		inputs[n++]=(parse(&p));
		while(*p != '\n') p++;
		p++;
	}
	memcpy(nodes,inputs,4*2*280000);
	sort(nodes,nodes+2*280000);//排序
	node_num = unique(nodes,nodes+2*280000) - nodes;//去重
	unordered_map<uint, int> idHash;
	for(int i=0; i<node_num; i++){idHash[nodes[i]] = i;}
	memset(len, 0, sizeof(len));
	memset(rlen, 0, sizeof(rlen));
	for(int i=0,a=0,b=0; i<n; i+=2){
		a=idHash[inputs[i]];
		b=idHash[inputs[i+1]];
		G[a][len[a]++]=b;//建立正向图
		RG[b][rlen[b]++]=a;//建立反向图
	}
	for(int i=0; i<node_num; i++) sort(G[i],G[i]+len[i]);//正向图的邻接表排序
	munmap(p_map, file_size);
}

void parse_to_chars(uint a, char *tmp, int *begin){
	int n=*begin;
	do{tmp[n++] = a%10+'0';}while((a/=10)>0.9);
	reverse(tmp+*begin, tmp+n);//因为上面转化为char数组后顺序是反的，所以这里把顺序变回来
	tmp[n++]=',';
	*begin=n;
}
void save(){
	int p=sprintf(buf,"%d\n",p3+p4+p5+p6+p7);
	int i, j;
	for(i=0; i<p3; i++){
		for(j=0; j<3; j++){
			parse_to_chars(nodes[ans3[i][j]], buf, &p);
		}
		buf[p-1]='\n';
	}
	for(i=0; i<p4; i++){
		for(j=0; j<4; j++){
			parse_to_chars(nodes[ans4[i][j]], buf, &p);
		}
		buf[p-1]='\n';
	}
	for(i=0; i<p5; i++){
		for(j=0; j<5; j++){
			parse_to_chars(nodes[ans5[i][j]], buf, &p);
		}
		buf[p-1]='\n';
	}
	for(i=0; i<p6; i++){
		for(j=0; j<6; j++){
			parse_to_chars(nodes[ans6[i][j]], buf, &p);
		}
		buf[p-1]='\n';
	}
	for(i=0; i<p7; i++){
		for(j=0; j<7; j++){
			parse_to_chars(nodes[ans7[i][j]], buf, &p);
		}
		buf[p-1]='\n';
	}
	int fd = open(resultFile.c_str(), O_RDWR|O_CREAT, 0666);
	lseek(fd, p-1, SEEK_SET);
	write(fd, "", 1);
	char* p_map =(char*)mmap(NULL, p, PROT_WRITE, MAP_SHARED, fd, 0);
	memcpy(p_map, buf, p);
	munmap(p_map, p);
	close(fd);
}

int p[7];
void dfs(int &head, int &cur, int dep){
	p[dep-1]=cur;
	for(int i=0,v=G[cur][0]; i<len[cur]; v=G[cur][++i]){
		if(v==head && dep>2){
			if(dep>2){
				switch(dep){
					case 3:
						memcpy(ans3[p3++], p, 12);
						break;
					case 4:
						memcpy(ans4[p4++], p, 16);
						break;
					case 5:
						memcpy(ans5[p5++], p, 20);
						break;
					case 6:
						memcpy(ans6[p6++], p, 24);
						break;
				}
			}
			continue;
		}
		if(dep==6 || avl[v]!=head || vis[v]) continue;
		vis[cur] = true;
		dfs(head, v, dep+1);
		vis[cur] = false;
	}
}

//通过正向图剪枝
void dfs1(int &head, int &cur, int dep){
	int length = len[cur], i=0;
	for(int v=G[cur][0]; i<length; v=G[cur][++i]){
		if(v < head || vis[v]) continue;
		avl[v] = head;
		if(dep == 2) continue;
		vis[cur] = true;
		dfs1(head, v, dep+1);
		vis[cur] = false;
	}
}
//通过反向图剪枝
void dfs2(int &head, int &cur, int dep){
	int length = rlen[cur], i=0;
	for(int v=RG[cur][0]; i<length; v=RG[cur][++i]){
		if(v < head || vis[v]) continue;
		avl[v] = head;
		if(dep == 3) continue;
		vis[cur] = true;
		dfs2(head, v, dep+1);
		vis[cur] = false;
	}
}
//第七层
void loop(int &u){
	p[0]=u;
	for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
		if(avl[v1]!=u) continue;
		for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]){
			if(avl[v2]!=u) continue;
			for(int k=0,v3=G[v2][0]; k<len[v2]; v3=G[v2][++k]){
				if(v3<u || v3==v1 || v3==u) continue;
				for(int m=0,v4=G[v3][0]; m<len[v3]; v4=G[v3][++m]){
					if(avl[v4]!=u || v4==v2 || v4==v1) continue;
					for(int n=0,v5=G[v4][0]; n<len[v4]; v5=G[v4][++n]){
						if(avl[v5]!=u || v5==v3 || v5==v2 || v5==v1) continue;
						for(int q=0,v6=G[v5][0]; q<len[v5]; v6=G[v5][++q]){
							if(avl[v6]!=u) continue;
							if(v6==v1 || v6==v2 || v6==v3 || v6==v4) continue;
							if(find(G[v6],G[v6]+len[v6], u)==G[v6]+len[v6])continue;
							p[1]=v1;
							p[2]=v2;
							p[3]=v3;
							p[4]=v4;
							p[5]=v5;
							p[6]=v6;
							memcpy(ans7[p7++], p, 28);
						}
					}
				}
			}
		}
	}
}

void solve(){
	memset(vis, 0, sizeof(vis));
	memset(avl, -1, sizeof(avl));
	for(int i=0;i<node_num;i++){
		if(len[i]!=0 && rlen[i]!=0){
			dfs1(i,i,1);//通过正向图剪枝
			dfs2(i,i,1);//通过反向图剪枝
			dfs(i,i,1);
			loop(i);
		}
	}
}

int main(int argc, char* argv[]){
	loadData_and_createGrap();
	solve();
	save();
	return 0;
}